﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Windows.Threading;
using System.Diagnostics;
using Microsoft.Devices;
using System.Runtime.Serialization;
using System.IO.IsolatedStorage;
using System.IO;
using Curling.CurlingServer;
using System.Threading;

namespace Curling
{
    [DataContractAttribute]
    public class GameManager
    {
        public List<Stone> Stones = new List<Stone>();
        public Stone DeliveryStone;

        [DataMemberAttribute]
        public ReplayManager replay { get; set; }

        //[DataMemberAttribute]
        public static int StonesCount = 16;

        [DataMemberAttribute]
        public int CurrentStone;

        [DataMemberAttribute]
        public TimeSpan CurrentGameTime = TimeSpan.FromMilliseconds(0);

        [DataMemberAttribute]
        public PlayerType Player1Type { get; set; }
        [DataMemberAttribute]
        public PlayerType Player2Type { get; set; }

        public GameData gameData { get; set; }

        static Random rand = new Random();

        public static VibrateController vibrate = VibrateController.Default;

        public const double Hackline = 135;
        public const double Backline = 337;
        public const double Teeline = 540;
        public const double Hogline = 1220;

        public const double Centerline = 240;

        public const double RinkWidth = 480;
        public const double RinkLength = 4798;

        private const double InitialPushVelocity = 500.0;                
        private const double RandomInitialRotation = 40.0;

        [DataMemberAttribute]
        public double StoneInitialRotation;

        [DataMemberAttribute]
        public GameState gameState;
        [DataMemberAttribute]
        public GameState gameStateReplay;

        [DataMemberAttribute]
        public PlayerColor ActivePlayer =  PlayerColor.Yellow;

        [DataMemberAttribute]
        public PlayerColor StartPlayer = PlayerColor.Yellow;

        public bool IsPersonActive
        {
            get
            {
               return (ActivePlayer == PlayerColor.Yellow && Player1Type == PlayerType.Person) || (ActivePlayer == PlayerColor.Red && Player2Type == PlayerType.Person);
            }
        }

        public bool IsComputerActive
        {
            get
            {
                return (ActivePlayer == PlayerColor.Yellow && Player1Type == PlayerType.Computer) || (ActivePlayer == PlayerColor.Red && Player2Type == PlayerType.Computer);
            }
        }

        public bool IsInternetActive
        {
            get
            {
                return (ActivePlayer == PlayerColor.Yellow && Player1Type == PlayerType.Internet) || (ActivePlayer == PlayerColor.Red && Player2Type == PlayerType.Internet);
            }
        }

        [DataMemberAttribute]
        public double LastStonePositionX;
        [DataMemberAttribute]
        public double LastStonePositionY;

        [DataMemberAttribute]
        public double LastBroomIntensity;

        public delegate void StoneAddedEventHandler(object sender, StoneAddedEventArgs e);
        public event StoneAddedEventHandler StoneAdded;

        public delegate void StonePostitonChangedEventHandler(object sender, StonePositionEventArgs e);
        public event StonePostitonChangedEventHandler DeliveredStonePostitonChanged;

        public delegate void ActivePlayerChangedEventHandler(object sender, EventArgs e);
        public event ActivePlayerChangedEventHandler ActivePlayerChanged;

        public delegate void GameEndedEventHandler(object sender, EventArgs e);
        public event GameEndedEventHandler GameEnded;

        public delegate void FallEventHandler(object sender, Fall e);
        public event FallEventHandler FallEvent;

        public GameManager()
        {
        }

        public void ReplayFinished()
        {
            foreach (Stone stone in Stones)
            {
                StoneReplayFrame stoneReplayFrame = replay.GetLastFrame(stone);

                stone.stoneEntity.X = stoneReplayFrame.X;
                stone.stoneEntity.Y = stoneReplayFrame.Y;
                stone.stoneEntity.PlayMoveSound(0.0);
                stone.stoneEntity.Rotation = stoneReplayFrame.Rotation;
                stone.stoneEntity.State = stoneReplayFrame.State;
            }
        }

        public void Update(double dT)
        {         
            if (replay != null && replay.IsPlaying)
            {
                CurrentGameTime = CurrentGameTime.Add(TimeSpan.FromSeconds(dT));

                replay.Update(CurrentGameTime);

                foreach (Stone stone in Stones)
                {
                    StoneReplayFrame stoneReplayFrame = replay.GetCurrentFrame(stone);

                    if (stoneReplayFrame != null)
                    {
                        if (stone.stoneEntity.X != stoneReplayFrame.X || stone.stoneEntity.Y != stoneReplayFrame.Y || stone.stoneEntity.Rotation != stoneReplayFrame.Rotation || stone.stoneEntity.State != stoneReplayFrame.State)
                        {
                            double LastStonePositionX = stone.stoneEntity.X;
                            double LastStonePositionY = stone.stoneEntity.Y;
                            
                            stone.stoneEntity.PlayMoveSound(stoneReplayFrame.Velocity);
                            
                            stone.stoneEntity.X = stoneReplayFrame.X;
                            stone.stoneEntity.Y = stoneReplayFrame.Y;
                            stone.stoneEntity.Rotation = stoneReplayFrame.Rotation;
                            stone.stoneEntity.State = stoneReplayFrame.State;

                            if (gameState == GameState.GameEnded)
                            {
                                if (stone.stoneEntity.ID == StonesCount - 1)
                                {
                                    DeliveredStonePostitonChanged(this, new StonePositionEventArgs() { X = stone.stoneEntity.x, dX = stone.stoneEntity.X - LastStonePositionX, Y = stone.stoneEntity.y - 600, dY = stone.stoneEntity.Y - LastStonePositionY });
                                }
                            }
                            else
                            {
                                if (stone.stoneEntity.ID == CurrentStone - 2)
                                {
                                    DeliveredStonePostitonChanged(this, new StonePositionEventArgs() { X = stone.stoneEntity.x, dX = stone.stoneEntity.X - LastStonePositionX, Y = stone.stoneEntity.y - 600, dY = stone.stoneEntity.Y - LastStonePositionY });
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                //if (IsInternetActive)
                //{                    
                //    CurrentGameTime = CurrentGameTime.Add(TimeSpan.FromSeconds(dT));
                //    Debug.WriteLine(CurrentGameTime.ToString());

                //    if (CurrentGameTime > TimeSpan.FromSeconds(0.0))
                //    {
                //        if (gameData.StoneGameFrames.Count > 0)
                //        {
                //            if (gameData.StoneGameFrames[gameData.StoneGameFrames.Count - 1].TimeStamp.Subtract(CurrentGameTime) < TimeSpan.FromSeconds(0.5))
                //            {
                //                Debug.WriteLine("waiting opponent");
                //                Thread.Sleep(1000);
                //            }

                //            for (int i = gameData.StoneGameFrames.Count - 1; i > 0; i--)
                //            {
                //                if (CurrentGameTime.CompareTo(gameData.StoneGameFrames[i].TimeStamp) > 0)
                //                {
                //                    //CurrentFrame = i;
                //                    //if (i > 0)
                //                    //{
                                    
                //                    Debug.WriteLine(i.ToString());
                //                        StoneReplayFrame stoneReplayFrame = gameData.StoneGameFrames[i - 1];

                //                        if (DeliveryStone.stoneEntity.X != stoneReplayFrame.X || DeliveryStone.stoneEntity.Y != stoneReplayFrame.Y || DeliveryStone.stoneEntity.Rotation != stoneReplayFrame.Rotation || DeliveryStone.stoneEntity.State != stoneReplayFrame.State)
                //                        {
                //                            double LastStonePositionX = DeliveryStone.stoneEntity.X;
                //                            double LastStonePositionY = DeliveryStone.stoneEntity.Y;

                //                            //DeliveryStone.stoneEntity.PlayMoveSound(stoneReplayFrame.Velocity);

                //                            DeliveryStone.stoneEntity.X = stoneReplayFrame.X;
                //                            DeliveryStone.stoneEntity.Y = stoneReplayFrame.Y;
                //                            DeliveryStone.stoneEntity.Rotation = stoneReplayFrame.Rotation;
                //                            DeliveryStone.stoneEntity.State = stoneReplayFrame.State;

                //                            DeliveredStonePostitonChanged(this, new StonePositionEventArgs() { X = DeliveryStone.stoneEntity.x, dX = DeliveryStone.stoneEntity.X - LastStonePositionX, Y = DeliveryStone.stoneEntity.y - 600, dY = DeliveryStone.stoneEntity.Y - LastStonePositionY });
                //                        }
                //                    //}

                //                    break;
                //                }
                //            }

                            
                //        }
                //    }
                //}
                //else
                {
                    if (gameState == GameState.StonePushed || gameState == GameState.StoneDelivered)
                    {
                        if (DeliveryStone != null)
                        {
                            CurrentGameTime = CurrentGameTime.Add(TimeSpan.FromSeconds(dT));

                            DeliveryStone.stoneEntity.Update(dT);

                            if (!DeliveryStone.stoneEntity.IsStatic)
                                DeliveredStonePostitonChanged(this, new StonePositionEventArgs() { X = DeliveryStone.stoneEntity.x, dX = DeliveryStone.stoneEntity.X - LastStonePositionX, Y = DeliveryStone.stoneEntity.y - 600, dY = DeliveryStone.stoneEntity.Y - LastStonePositionY });

                            DeliveryStone.stoneEntity.CheckPosition(gameState);

                            if (DeliveryStone.stoneEntity.Fall != null)
                            {
                                DeliveryStone.stoneEntity.State = StoneState.InOut;
                                FallEvent(DeliveryStone, DeliveryStone.stoneEntity.Fall);
                            }

                            //Debug.WriteLine(ReplayManager.IsEnabled.ToString());
                            if (gameState == GameState.StonePushed || gameState == GameState.StoneDelivered && ReplayManager.IsEnabled)
                            {
                                if (replay != null)
                                {
                                    StoneReplayFrame stoneReplayFrame = replay.AddFrame(DeliveryStone, CurrentGameTime);

                                    //if (gameData != null && stoneReplayFrame != null && IsPersonActive && (Player1Type == PlayerType.Internet ||Player2Type == PlayerType.Internet))
                                    //    gameData.AddStoneFrame(stoneReplayFrame, DeliveryStone.stoneEntity.ID);
                                }
                            }

                            if (DeliveryStone.stoneEntity.Y + 2 * StoneEntity.Radius > GameManager.RinkLength - GameManager.Hogline)
                            {
                                for (int i = 0; i < Stones.Count; i++)
                                {
                                    if (Stones[i] != DeliveryStone)
                                    {
                                        if (Stones[i].stoneEntity.State != StoneState.WaitDelivery)
                                        {
                                            Stones[i].stoneEntity.Update(dT);

                                            Stones[i].stoneEntity.CheckPosition(gameState);

                                            if (Stones[i].stoneEntity.Fall != null)
                                            {
                                                Stones[i].stoneEntity.State = StoneState.InOut;
                                                //Stones.RemoveAt(i);
                                                //FallEvent(StonesDelivered[i], StonesDelivered[i].Fall);
                                            }
                                        }

                                        if (replay != null && ReplayManager.IsEnabled)
                                        {
                                            StoneReplayFrame stoneReplayFrame = replay.AddFrame(Stones[i], CurrentGameTime);

                                            //if (gameData != null && stoneReplayFrame != null && IsPersonActive && (Player1Type == PlayerType.Internet || Player2Type == PlayerType.Internet))
                                            //    gameData.AddStoneFrame(stoneReplayFrame, Stones[i].stoneEntity.ID);
                                        }
                                    }
                                }

                                ProcessCollisions();
                            }

                            LastStonePositionX = DeliveryStone.stoneEntity.X;
                            LastStonePositionY = DeliveryStone.stoneEntity.Y;

                            if (gameState == GameState.StoneDelivered)
                            {
                                bool EndRound = true;

                                if (!DeliveryStone.stoneEntity.IsProceed)
                                {
                                    EndRound = false;
                                }
                                else
                                {
                                    foreach (Stone stone in Stones)
                                    {
                                        if (!stone.stoneEntity.IsProceed && stone.stoneEntity.State != StoneState.WaitDelivery)
                                        {
                                            EndRound = false;
                                            break;
                                        }
                                    }
                                }

                                if (EndRound)
                                {
                                    gameState = GameState.RoundEnded;

                                    SoundManager.PlayBroomSound(0.0);

                                    DeliveryStone.stoneEntity.soundManager.PlayMoveSound(0.0);

                                    foreach (Stone stone in Stones)
                                    {
                                        stone.stoneEntity.soundManager.PlayMoveSound(0.0);
                                    }

                                    replay.StopRecord(CurrentGameTime);

                                    DeliveryStone = null;

                                    CurrentGameTime = TimeSpan.FromMilliseconds(0);
                                    ActivePlayerChanged(this, EventArgs.Empty);
                                }
                            }
                        }
                    }
                }
            }
        }

        private void ProcessCollisions()
        {
            for (int i = 0; i < Stones.Count - 1; i++)
            {
                for (int j = i + 1; j < Stones.Count; j++)
                {
                    if ((!Stones[i].stoneEntity.IsStatic || !Stones[j].stoneEntity.IsStatic) && Stones[i].stoneEntity.State == StoneState.OnRink && Stones[j].stoneEntity.State == StoneState.OnRink)
                    {
                        double Impulse = Stones[i].stoneEntity.CheckCollision(Stones[j].stoneEntity);

                        if (Impulse > 0.0)
                        {
                            SoundManager.PlayStoneHit(Math.Min(Impulse / 200, 1.0));

                            vibrate.Start(TimeSpan.FromMilliseconds(Math.Max(Math.Min(Impulse / 4, 60), 20)));

                            if (replay != null)
                            {
                                replay.AddHit(Impulse, CurrentGameTime);
                            }
                        }
                    }
                }
            }
        }

        public void UseBroom(double Intensity, double dT)
        {
            if (gameState == GameState.StoneDelivered)
            {
                if (LastBroomIntensity != 0.0 || Intensity != 0.0)
                {
                    Intensity = Intensity * 0.4 + LastBroomIntensity * 0.6;
                    Intensity = (Intensity < 0.1) ? 0.0 : Intensity;
                }
                
                if (Intensity == 0.0)
                {
                    DeliveryStone.stoneEntity.Friction = StoneEntity.FrictionWithoutPlayer;
                    DeliveryStone.stoneEntity.AngularFriction = StoneEntity.AngularFrictionWithoutBroom;

                    DeliveryStone.stoneEntity.Curl = 1.0;

                    SoundManager.PlayBroomSound(0.0);
                }
                else
                {
                    double A = Math.Min(Intensity / dT * 0.0004, 1.0);

                    DeliveryStone.stoneEntity.Friction = StoneEntity.FrictionWithBroom * A + StoneEntity.FrictionWithoutPlayer * (1 - A);
                    DeliveryStone.stoneEntity.AngularFriction = StoneEntity.AngularFrictionWithBroom * A + StoneEntity.AngularFrictionWithoutBroom * (1 - A);

                    DeliveryStone.stoneEntity.Curl = 1.0 - A;

                    SoundManager.PlayBroomSound(A);
                }
                LastBroomIntensity = Intensity;
            }
        }

        public void StoneToStart()
        {
            if (CurrentStone < StonesCount)
            {
                DeliveryStone = Stones[CurrentStone];

                DeliveryStone.stoneEntity.X = Centerline;
                DeliveryStone.stoneEntity.Y = Hackline;

                CurrentStone++;

                DeliveryStone.stoneEntity.State = StoneState.OnStart;
                DeliveryStone.stoneEntity.Save();

                gameState = GameState.StoneOnStart;
            }
            else
            {
                gameState = GameState.GameEnded;
                GameEnded(this, EventArgs.Empty);
            }
        }

        public void NewRound()
        {
            CurrentStone = 0;

            GenerateStones(StonesCount, true);
            StonesToStartPositions();

            StoneToStart();
        }

        public int GetRoundResult()
        {
            double Player1MinLength = double.MaxValue;
            double Player2MinLength = double.MaxValue;

            for (int i = 0; i < Stones.Count; i++)
            {
                if (Stones[i].stoneEntity.stoneColor == StoneColor.Yellow)
                {
                    Player1MinLength = Math.Min(Player1MinLength, Stones[i].stoneEntity.DistanceToButton);
                }

                if (Stones[i].stoneEntity.stoneColor == StoneColor.Red)
                {
                    Player2MinLength = Math.Min(Player2MinLength, Stones[i].stoneEntity.DistanceToButton);
                }                
            }

            int Points = 0;

            for (int i = 0; i < Stones.Count; i++)
            {
                if (Stones[i].stoneEntity.DistanceToButton < Math.Max(Player1MinLength, Player2MinLength))
                {
                    if (Stones[i].stoneEntity.DistanceToButton < GameManager.Teeline - GameManager.Backline + StoneEntity.Radius + 2.0)
                    {
                        Points++;
                    }
                }
            }

            return Points * ((Player1MinLength < Player2MinLength) ? 1 : -1);
        }

        public void AddRotationImpulse(double RotationImpulse, double dT)
        {
            if (DeliveryStone != null)
            {
                DeliveryStone.stoneEntity.AddRotationImpulse(RotationImpulse, dT);
            }
        }

        public void GenerateStones(int n, bool CreateEntity)
        {
            int k = (StartPlayer == PlayerColor.Yellow) ? 1 : 0;

            if (Stones.Count == 0)
            {                
                //Stones.Clear();

                for (int i = 0; i < n; i++)
                {
                    Stone stone;

                    if (i % 2 == k)
                    {
                        stone = new Stone(StoneColor.Red, i, CreateEntity);
                    }
                    else
                    {
                        stone = new Stone(StoneColor.Yellow, i, CreateEntity);
                    }

                    if (StoneAdded != null)
                        StoneAdded(this, new StoneAddedEventArgs() { stone = stone });

                    Stones.Add(stone);
                }
            }
            else
            {
                for (int i = 0; i < n; i++)
                {
                    if (i % 2 == k)
                    {
                        Stones[i].stoneEntity.stoneColor = StoneColor.Red;
                        Stones[i].ChangeColor(StoneColor.Red);
                    }
                    else
                    {
                        Stones[i].stoneEntity.stoneColor = StoneColor.Yellow;
                        Stones[i].ChangeColor(StoneColor.Yellow);
                    }
                }
            }
        }

        private void StonesToStartPositions()
        {
            int k = (StartPlayer == PlayerColor.Yellow) ? 0 : 1;

            for (int i = 0; i < StonesCount; i++)
            {
                int n = StonesCount; 
                if (i % 2 == k)
                {
                    Stones[n - i - 1].stoneEntity.X = Centerline * 2 - 50 - ((int)((i / 2) / 4)) * (StoneEntity.Radius * 2 + 4);
                    Stones[n - i - 1].stoneEntity.Y = 50 + ((i / 2) % 4) * (StoneEntity.Radius * 2 + 4);
                    Stones[n - i - 1].stoneEntity.Rotation = 0.0;
                    Stones[n - i - 1].stoneEntity.State = StoneState.WaitDelivery;
                }
                else
                {
                    Stones[n - i - 1].stoneEntity.X = 50 + ((int)((i / 2) / 4)) * (StoneEntity.Radius * 2 + 4);
                    Stones[n - i - 1].stoneEntity.Y = 50 + ((i / 2) % 4) * (StoneEntity.Radius * 2 + 4);
                    Stones[n - i - 1].stoneEntity.Rotation = 0.0;
                    Stones[n - i - 1].stoneEntity.State = StoneState.WaitDelivery;
                }
                Stones[i].stoneEntity.DistanceToButton = double.MaxValue;
            }
        }

        public void ChooseStartPlayer(int RoundResult)
        {
            if (RoundResult > 0)
            {
                ActivePlayer = PlayerColor.Yellow;
                StartPlayer = PlayerColor.Yellow;
            }
            else if (RoundResult < 0)
            {
                ActivePlayer = PlayerColor.Red;
                StartPlayer = PlayerColor.Red;
            }
            //else
            //{
            //    if (ActivePlayer == PlayerColor.Yellow)
            //    {
            //        ActivePlayer = PlayerColor.Red;
            //    }
            //    else
            //    {
            //        ActivePlayer = PlayerColor.Yellow;
            //    }
            //}
        }

        public void PushStone()
        {
            if (DeliveryStone != null)
            {
                CurrentGameTime = TimeSpan.FromMilliseconds(0);

                replay = new ReplayManager(Stones);

                DeliveryStone.stoneEntity.Friction = StoneEntity.FrictionWithPlayer;
                DeliveryStone.stoneEntity.VelocityY = InitialPushVelocity * Math.Cos(DeliveryStone.stoneEntity.Rotation / 180.0 * Math.PI);
                DeliveryStone.stoneEntity.VelocityX = InitialPushVelocity * Math.Sin(DeliveryStone.stoneEntity.Rotation / 180.0 * Math.PI);
                DeliveryStone.stoneEntity.IsProceed = false;

                StoneInitialRotation = DeliveryStone.stoneEntity.Rotation;

                DeliveryStone.stoneEntity.State = StoneState.OnRink;

                gameState = GameState.StonePushed;
            }
        }

        public void LeaveStone()
        {
            if (DeliveryStone != null)
            {
                DeliveryStone.stoneEntity.Friction = StoneEntity.FrictionWithoutPlayer;
                DeliveryStone.stoneEntity.AngularVelocity += (rand.NextDouble() + rand.NextDouble() - 1.0) * RandomInitialRotation;

                gameState = GameState.StoneDelivered;
            }
        }

        public void RotateDeliveryStone(double Rotation)
        {
            if (DeliveryStone != null)
            {
                if (gameState == GameState.StoneOnStart)
                {
                    DeliveryStone.stoneEntity.Rotation = Rotation;
                }
            }
        }

        public void Save()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    Store.CreateDirectory("GameManager");
                }

                string Path = "\\GameManager\\GameManager.xml";

                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(Path, FileMode.Create, Store))
                {
                    DataContractSerializer dtaContractSerializer = new DataContractSerializer(typeof(GameManager));
                    dtaContractSerializer.WriteObject(stream, this);
                }
            }
        }

        public static GameManager Load()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    Store.CreateDirectory("GameManager");
                }

                string Path = "\\GameManager\\GameManager.xml";

                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(Path, FileMode.OpenOrCreate, Store))
                {
                    if (stream.Length > 0)
                    {
                        DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(GameManager));

                        try
                        {
                            GameManager gameManager = dataContractSerializer.ReadObject(stream) as GameManager;

                            return gameManager;
                        }
                        catch(Exception)
                        {
                            return null;
                        }
                    }
                    return null;
                }
            }
        }

        public static void Delete()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    return;
                }

                string Path = "\\GameManager\\GameManager.xml";

                if (Store.FileExists(Path))
                {
                    try
                    {
                        Store.DeleteFile(Path);
                    }
                    catch (Exception)
                    { }
                }
            }
        }

        public static bool IsExists()
        {
            using (IsolatedStorageFile Store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!Store.DirectoryExists("GameManager"))
                {
                    return false;
                }

                string Path = "\\GameManager\\GameManager.xml";

                if (Store.FileExists(Path))
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(Path, FileMode.OpenOrCreate, Store))
                    {
                        if (stream.Length > 0)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }

        public static double ConvertX(double X)
        {
            return X;
        }

        public static double ConvertXBack(double X)
        {
            return X;
        }

        public static double ConvertY(double Y)
        {
            return 4924 - Y; //4800 + 124
        }

        public static double ConvertYBack(double Y)
        {
            return 4924 - Y; //4800 + 124
        }
    }

    public enum GameState
    { 
        StoneOnStart,
        StonePushed,
        StoneDelivered,
        RoundEnded,
        GameEnded,
        MatchEnded
    }
}
